package com.yfp.operation.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.yfp.operation.domain.DeviceComboPlanNumDO;
import com.yfp.operation.domain.MachineDO;
import com.yfp.operation.domain.dto.ComboMarginDTO;
import com.yfp.operation.domain.vo.*;
import com.yfp.operation.mapper.DeviceCurrentComboStockMapper;
import com.yfp.operation.mapper.StatisticsMapper;
import com.yfp.operation.service.*;
import com.yfp.operation.domain.vo.*;
import com.yfp.operation.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Service;
import com.yfp.common.core.constant.MachineInventory;
import jakarta.annotation.Resource;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StatisticsServiceImpl implements StatisticsService {

    @Resource
    private MachineService machineService;
    @Resource
    private DeviceCurrentComboStockMapper deviceCurrentComboStockMapper;
    @Resource
    private OrderListService orderListService;
    @Resource
    private OrderDetailService orderDetailService;
    @Resource
    private ComboService comboService;
    @Resource
    private MachineDamageDetailService machineDamageDetailService;
    @Resource
    private DeviceComboPlanNumService deviceComboPlanNumService;
    @Resource
    private OrderComboService orderComboService;
    @Resource
    private StatisticsMapper statisticsMapper;

    /**
     * 数据统计
     * @param machineId 设备id
     * @return
     */
    @Override
    public RegulateDataVO getDataStatistics(String machineId) {

        // 获取设备信息
        MachineDO machine = machineService.getMachine(machineId);
        if (machine == null) {
            log.info("设备信息获取失败,设备id:{}",machineId);
            return new RegulateDataVO();
        }

//        List<DeviceComboPlanNumDO> dcpnList = deviceComboPlanNumService.getAll(machineId);
        List<PlanNumVO> dcpnList = deviceComboPlanNumService.getAll(machineId);

        Map<String, PlanNumVO> planNumDOMap = dcpnList.stream().collect(Collectors.toMap(PlanNumVO::getComboId, Function.identity()));

        // 获取设备最大存储量
        Integer threshold = 0;
        // 设备类型  2二代机  3三代机  4四代机
        Integer machineType = machine.getMachineType();
        switch (machineType) {
            case 2 :
                threshold = MachineInventory.ZHONGJI;
                break;
            case 3 :
                threshold = MachineInventory.ZIYAN;
                break;
            case 4 :
                threshold = MachineInventory.FOUR;
                break;
            case 5 :
                threshold = MachineInventory.FIVE;
                break;

        }

        String machineName = machine.getMachineName();

        RegulateDataVO regulateDataVO = new RegulateDataVO();
        // 今日总投放量
        Long putCount = 0L;
        // 已售总数
        Long saleCount = 0L;
        // 剩余数量
        Long surplusCount = 0L;
        // 退款总数量
        Long refundCount = 0L;
        // 创建单品余量集合
        List<ComboMarginDTO> comboMargins1DTO = new ArrayList<>();

        // 获取当前设备今日所有订单号
        List<String> orderSnList = orderListService.getOrderSnList(machineId);
        // 获取当前设备今日退款订单号
        List<OrderDetailVO> refundOrders = orderListService.getRefundId(machine);
        Map<String, BigDecimal> refundMap = null;
        if (!refundOrders.isEmpty()) {
            refundMap = refundOrders.stream().collect(Collectors.toMap(OrderDetailVO::getPackageId, OrderDetailVO::getNum));
        }

        // 获取当日卖出的每个套餐情况
        Map<String, Long> detailMap = new HashMap<>();
        if (orderSnList != null) {
            orderSnList.forEach(orderSn -> {
                List<OrderDetailVO> orderDetailVOS = orderDetailService.getDetail(orderSn);
                log.info("售出套餐详情:{}",orderDetailVOS);
                if (orderDetailVOS != null) {
                    for (OrderDetailVO orderDetailVO : orderDetailVOS) {
                        String packageId = orderDetailVO.getPackageId();
                        BigDecimal num = orderDetailVO.getNum();
                        detailMap.put(packageId, detailMap.getOrDefault(packageId, 0L) + num.longValue());
                    }
                }
            });

            // 遍历已售的套餐情况集合
            for (String key : detailMap.keySet()) {
                // 根据套餐id查询套餐名称
                String name = comboService.getName(key);

                // 创建单品余量对象
                ComboMarginDTO comboMarginDTO = new ComboMarginDTO();
                comboMarginDTO.setComboName(name);
                comboMarginDTO.setComboId(key);
                comboMarginDTO.setSaleCount(detailMap.get(key));
                // 加入单品余量集合
                comboMargins1DTO.add(comboMarginDTO);
            }
        }
        log.info("售出余量集合:{}",comboMargins1DTO);


        List<ComboMarginDTO> comboMargins2DTO = new ArrayList<>();
        // 获取该设备库存情况
        List<DeviceCurrentComboStockVO> deviceCurrentComboStockVOS = deviceCurrentComboStockMapper.getComboCount(machineId);
        log.info("库存集合:{}",deviceCurrentComboStockVOS);
        if (deviceCurrentComboStockVOS != null) {
            for (DeviceCurrentComboStockVO deviceCurrentComboStockVO : deviceCurrentComboStockVOS) {
                String comboId = deviceCurrentComboStockVO.getComboId();
                Long num = deviceCurrentComboStockVO.getNum();
                // 根据套餐id查询套餐名称
                String name = comboService.getName(comboId);
                // 创建单品余量对象
                ComboMarginDTO comboMarginDTO = new ComboMarginDTO();
                comboMarginDTO.setComboName(name);
                comboMarginDTO.setComboId(comboId);
                comboMarginDTO.setSurplusCount(num);

                // 退款数量
                comboMarginDTO.setRefundCount(0L);
                if (null != refundMap) {
                    if (refundMap.containsKey(comboId)) {
                        refundCount += refundMap.get(comboId).longValue();
                        comboMarginDTO.setRefundCount(refundMap.get(comboId).longValue());
                    }
                }
                // 售出数量默认0
                comboMarginDTO.setSaleCount(0L);
                comboMarginDTO.setPutCount(0L);
                if (planNumDOMap.containsKey(comboId)) {
                    PlanNumVO planNumVO = planNumDOMap.get(comboId);
                    // 投放数量
                    comboMarginDTO.setPutCount(planNumVO.getNum().longValue());
                }
                // 加入集合
                comboMargins2DTO.add(comboMarginDTO);
            }
            putCount = comboMargins2DTO.stream().mapToLong(ComboMarginDTO::getPutCount).sum();

        }

        // 总投放数
        regulateDataVO.setCount(putCount);

        log.info("套餐余量实体类集合:{}",comboMargins2DTO);


        // 售出map
        Map<String, ComboMarginDTO> stringComboMarginHashMap1 = new HashMap<>();
        if (!comboMargins1DTO.isEmpty()) {
            for (ComboMarginDTO comboMarginDTO : comboMargins1DTO) {
                stringComboMarginHashMap1.put(comboMarginDTO.getComboId(), comboMarginDTO);
            }
        }

        // 库存map
        Map<String, ComboMarginDTO> stringComboMarginHashMap2 = new HashMap<>();
        if (!comboMargins2DTO.isEmpty()) {
            for (ComboMarginDTO comboMarginDTO : comboMargins2DTO) {
                stringComboMarginHashMap2.put(comboMarginDTO.getComboId(), comboMarginDTO);
            }
        }


        // 单品余量集合
        List<ComboMarginDTO> comboMarginDTOS = new ArrayList<>();

        log.info("售出map:{}",stringComboMarginHashMap1);
        log.info("库存map:{}",stringComboMarginHashMap2);

        if (!stringComboMarginHashMap2.keySet().isEmpty()) {
            // 遍历key集合
            for (String key : stringComboMarginHashMap2.keySet()) {
                // 判断售出map中是否包含该key
                if (stringComboMarginHashMap1.containsKey(key)) {
                    ComboMarginDTO comboMarginDTO2 = stringComboMarginHashMap2.get(key);
                    ComboMarginDTO comboMarginDTO1 = stringComboMarginHashMap1.get(key);
                    comboMarginDTO2.setSaleCount(comboMarginDTO1.getSaleCount());
//                    comboMarginDTO2.setPutCount(comboMarginDTO1.getSaleCount() + comboMarginDTO2.getSurplusCount());
                    saleCount += comboMarginDTO2.getSaleCount();
                    surplusCount += comboMarginDTO2.getSurplusCount();
                    comboMarginDTOS.add(comboMarginDTO2);
                } else {
                    ComboMarginDTO comboMarginDTO2 = stringComboMarginHashMap2.get(key);
                    saleCount += comboMarginDTO2.getSaleCount();
                    surplusCount += comboMarginDTO2.getSurplusCount();
                    comboMarginDTOS.add(comboMarginDTO2);
                }
            }
        }



        // 上货率
        BigDecimal divide = new BigDecimal(putCount).multiply(new BigDecimal(100)).divide(new BigDecimal(threshold), 0, RoundingMode.HALF_UP);
        Integer goodsRate = divide.intValue();
        // 上货率
        regulateDataVO.setGoodsRate(goodsRate);
        // 已售总数
        regulateDataVO.setSaleCount(saleCount);
        // 退款总数
        regulateDataVO.setRefundCount(refundCount);
        // 剩余总数
        regulateDataVO.setSurplusCount(surplusCount);
        if (putCount != 0) {
            // 销售进度
//            BigDecimal divide1 = new BigDecimal(saleCount - refundCount).multiply(new BigDecimal(100)).divide(new BigDecimal(putCount), 0, RoundingMode.HALF_UP);
            BigDecimal divide1 = new BigDecimal(saleCount).multiply(new BigDecimal(100)).divide(new BigDecimal(putCount), 0, RoundingMode.HALF_UP);
            Integer marketSchedule = divide1.intValue();
            regulateDataVO.setMarketSchedule(marketSchedule);
        }

        // 设备名称
        regulateDataVO.setMachineName(machineName);
        // 单品余量
        regulateDataVO.setComboMarginDTOList(comboMarginDTOS);


        // 昨日报损数量
        Integer reportNum = machineDamageDetailService.getReportNum(machineId);
        if (reportNum == null) {
            reportNum = 0;
        }

        // 昨日投放量
        Integer count = deviceComboPlanNumService.getByMachineId(machineId);
        if (count == null) {
            count = 0;
        }

        log.info("设备id:{},昨日投放量:{},昨日报损数:{}",machineId,count,reportNum);
        if (count != 0) {

            // 昨日报损率
//            BigDecimal divide2 = new BigDecimal(reportNum).divide(new BigDecimal(count), 0, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
            int a = count;
            int b = reportNum;
            double div = NumberUtil.div(b, a, 2, RoundingMode.UP);
            double mul = NumberUtil.mul(div, 100);
            regulateDataVO.setBreakageRete((int) mul);
        }

        // 获取该设备昨日下单的号码
        List<String> mobileList = orderListService.getUserMobile(machineId);
        // 昨日新增客户数
        Long addClientCount = 0L;
        if (!mobileList.isEmpty()) {
            // 筛选出存在历史订单的号码   今天和昨天不查
            List<String> list = orderListService.getAgain(mobileList);
            // 存在则不是新用户  减去
            addClientCount = ((long)mobileList.size()) - ((long) list.size());
        }

        // 昨日新增客户数量
        regulateDataVO.setAddClientCount(addClientCount);
        log.info("获取设备数据统计成功，设备id:{},数据:{}",machineId,regulateDataVO);
        return regulateDataVO;
    }

    @Override
    public List<MachineDayData> getMachineDayData() {
        List<MachineDayData> machineDayDatas= new ArrayList<>();
        MachineDayData machineDayData = null;
        List<MachineDO> machineDOList = machineService.findAll();
        for (MachineDO machineDO : machineDOList) {
            // 查询同步计划, 查询投放量
            List<SyncPlan> sncPlan = statisticsMapper.findSyncPlanByMachineId(machineDO.getMachineId(), null);
            // 统计当天售卖数量
            List<Sale> sales = orderListService.countSale(machineDO.getMachineId());
            // 查询库存
            List<ComboInventory> comboInventory = statisticsMapper.findComboInventoryByMachineId(machineDO.getMachineId());
            Map<String, ComboInventory> comboInventoryMap = comboInventory.stream().collect(Collectors.toMap(ComboInventory::getComboId, s -> s));

            // 查询当天报损
            List<ComboLosses> comboLosses = statisticsMapper.findComboLossesByMachineId(machineDO.getMachineId());
            Map<String, ComboLosses> comboLossesMap = comboLosses.stream().collect(Collectors.toMap(ComboLosses::getComboId, s -> s));
            // 查询第一次投放
            DeviceComboPlanNumDO deviceComboPlanNumDO = deviceComboPlanNumService.getDayFirstByMacineId(machineDO.getMachineId());
            List<SyncPlan> fristSncPlan = null;
            Map<String, SyncPlan> syncPlanMap = null;
            if (deviceComboPlanNumDO != null && deviceComboPlanNumDO.getCreateTime() != null){
                fristSncPlan  = statisticsMapper.findSyncPlanByMachineId(machineDO.getMachineId(), deviceComboPlanNumDO.getCreateTime());
                syncPlanMap = fristSncPlan.stream().collect(Collectors.toMap(SyncPlan::getComboId, s -> s));
            }
            for (SyncPlan syncPlan : sncPlan) {
                machineDayData = new MachineDayData();
                machineDayData.setMachineId(machineDO.getMachineId());
                machineDayData.setMachineName(machineDO.getMachineName());
                machineDayData.setComboId(syncPlan.getComboId());
                machineDayData.setSumLaunch(syncPlan.getComboNum());
                machineDayData.setDevOrderMonay(BigDecimal.valueOf(0));
                machineDayData.setDevSaleNum(0);
                machineDayData.setMiniOrderMonay(BigDecimal.valueOf(0));
                machineDayData.setMiniSaleNum(0);
                machineDayData.setSaleNum(0);
                for (Sale sale : sales) {
                    if (sale.getComboId().equals(machineDayData.getComboId()) && sale.getOrderType() == 0){
                        machineDayData.setMiniOrderMonay(sale.getMoney());
                        machineDayData.setMiniSaleNum(sale.getCount());
                    } else if (sale.getComboId().equals(machineDayData.getComboId()) && sale.getOrderType() == 1){
                        machineDayData.setDevOrderMonay(sale.getMoney());
                        machineDayData.setDevSaleNum(sale.getCount());
                    }
                }
                machineDayData.setSaleNum(machineDayData.getDevSaleNum()+machineDayData.getMiniSaleNum());
                machineDayData.setOrderMonay(machineDayData.getDevOrderMonay().add(machineDayData.getMiniOrderMonay()));
                ComboInventory comboInventory1 = comboInventoryMap.get(machineDayData.getComboId());
                ComboLosses comboLosses1 = comboLossesMap.get(machineDayData.getComboId());
                if ( null != syncPlanMap){
                    SyncPlan syncPlan1 = syncPlanMap.get(syncPlan.getComboId());
                    if (null != syncPlan1 && null != syncPlan1.getComboNum()){
                        machineDayData.setLaunch(syncPlan1.getComboNum());
                        // 计算售卖率,取第一次投放计划
                        if (machineDayData.getLaunch() > 0){
                            BigDecimal dev = BigDecimal.valueOf(machineDayData.getDevSaleNum()).divide(BigDecimal.valueOf(machineDayData.getLaunch()), 4, BigDecimal.ROUND_HALF_UP);
                            machineDayData.setDevOrderRito(dev);
                            BigDecimal mini = BigDecimal.valueOf(machineDayData.getMiniSaleNum()).divide(BigDecimal.valueOf(machineDayData.getLaunch()), 4, BigDecimal.ROUND_HALF_UP);
                            machineDayData.setMiniOrderRito(mini);
                        }
                    } else {
                        machineDayData.setLaunch(0);
                    }
                }

                if (null != comboInventory1){
                    machineDayData.setComboNum(comboInventory1.getComboNum());
                    machineDayData.setComboName(comboInventory1.getName());
                } else {
                    machineDayData.setComboNum(0);
                    machineDayData.setComboName("");
                }
                if (null != comboLosses1){
                    machineDayData.setReportNum(comboLosses1.getReportNum());
                } else {
                    machineDayData.setReportNum(0);
                }
                machineDayDatas.add(machineDayData);
            }
        }
        return machineDayDatas;
    }
}
